﻿using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Text.Json;

namespace Framework.Utility.Helper
{
    public class IpLocationHelper
    {

        /// <summary>
        /// 获取本地 IP 地址
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static string LocalIPAddress()
        {
            var host = Dns.GetHostEntry(Dns.GetHostName());
            // 获取第一个IP地址
            var ipAddress = host.AddressList
            .FirstOrDefault(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
            if (ipAddress == null)
            {
                throw new Exception("找不到此计算机的IPv4地址");
            }
            return ipAddress.ToString();
        }

        /// <summary>
        ///  获取本地IP地址列表
        /// </summary>
        /// <returns></returns>
        public static string[] GetAllLocalIPAddresses()
        {
            var ipAddressList = NetworkInterface.GetAllNetworkInterfaces()
                .Where(n => n.OperationalStatus == OperationalStatus.Up)
                .SelectMany(n => n.GetIPProperties().UnicastAddresses)
                .Where(a => a.Address.AddressFamily == AddressFamily.InterNetwork)
                .Select(a => a.Address.ToString())
                .ToArray();
            return ipAddressList;
        }
        /// <summary>
        /// 获取外网 IP 地址
        /// </summary>
        /// <returns></returns>
        public static async Task<string> GetPublicIPAddressAsync()
        {
            using (var client = new HttpClient())
            {
                string url = "http://ifconfig.me/ip";
                var response = await client.GetStringAsync(url);
                return response.Trim();
            }
        }

        #region IP位置查询
        public static async Task<string> GetIpLocation(string ipAddress)
        {
            string ipLocation = string.Empty;
            try
            {
                if (!IsInnerIP(ipAddress))
                {
                    ipLocation =await GetIpLocationFromTaoBao(ipAddress);
                    if (string.IsNullOrEmpty(ipLocation))
                    {
                        ipLocation =await GetIpLocationFromPCOnline(ipAddress);
                    }
                }
            }
            catch (Exception ex)
            {
                NLogHelper.Error(ex);
            }
            return ipLocation;
        }

        private static async Task<string> GetIpLocationFromTaoBao(string ipAddress)
        {
            string url = "http://ip.taobao.com/service/getIpInfo2.php";
            string postData = string.Format("ip={0}", ipAddress);
            var jsonContent = new StringContent(JsonSerializer.Serialize(postData), Encoding.UTF8, "application/json");
            try
            {
                var httpclient = HttpClientFactoryUtil.Instance.CreateClient();
                var response = await httpclient.PostAsync(url, jsonContent);
                response.EnsureSuccessStatusCode();
                var result = await response.Content.ReadAsStringAsync();

                string ipLocation = string.Empty;
                if (!string.IsNullOrEmpty(result))
                {
                    var json = JsonHelper.ToJObject(result);
                    var jsonData = json["data"];
                    if (jsonData != null)
                    {
                        ipLocation = jsonData["region"] + " " + jsonData["city"];
                        ipLocation = ipLocation.Trim();
                    }
                }
                return ipLocation;
            }
            catch (Exception)
            {

                return string.Empty;
            }
  
        }

        private static async Task<string> GetIpLocationFromPCOnline(string ipAddress)
        {
            var httpclient = HttpClientFactoryUtil.Instance.CreateClient(); 
            string url = "http://whois.pconline.com.cn/ip.jsp?ip=" + ipAddress; 
            httpclient.DefaultRequestHeaders.Add("Content-Type", "text/html; charset=gb2312");
            var response = await httpclient.GetAsync(url);
            if (!response.IsSuccessStatusCode) { 
                return string.Empty;
            }
            response.EnsureSuccessStatusCode();
            var _html = await response.Content.ReadAsStringAsync(); 
            string ipLocation = string.Empty;
            if (!string.IsNullOrEmpty(_html))
            {
                var resultArr = _html.Split(' ');
                ipLocation = resultArr[0].Replace("省", "  ").Replace("市", "");
                ipLocation = ipLocation.Trim();
            }
            return ipLocation;
        }
        #endregion

        #region 判断是否是外网IP
        public static bool IsInnerIP(string ipAddress)
        {
            bool isInnerIp = false;
            long ipNum = GetIpNum(ipAddress);
            /**
                私有IP：A类 10.0.0.0-10.255.255.255
                            B类 172.16.0.0-172.31.255.255
                            C类 192.168.0.0-192.168.255.255
                当然，还有127这个网段是环回地址 
           **/
            long aBegin = GetIpNum("10.0.0.0");
            long aEnd = GetIpNum("10.255.255.255");
            long bBegin = GetIpNum("172.16.0.0");
            long bEnd = GetIpNum("172.31.255.255");
            long cBegin = GetIpNum("192.168.0.0");
            long cEnd = GetIpNum("192.168.255.255");
            isInnerIp = IsInner(ipNum, aBegin, aEnd) || IsInner(ipNum, bBegin, bEnd) || IsInner(ipNum, cBegin, cEnd) || ipAddress.Equals("127.0.0.1");
            return isInnerIp;
        }

        /// <summary>
        /// 把IP地址转换为Long型数字
        /// </summary>
        /// <param name="ipAddress">IP地址字符串</param>
        /// <returns></returns>
        private static long GetIpNum(string ipAddress)
        {
            string[] ip = ipAddress.Split('.');
            long a = int.Parse(ip[0]);
            long b = int.Parse(ip[1]);
            long c = int.Parse(ip[2]);
            long d = int.Parse(ip[3]);

            long ipNum = a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
            return ipNum;
        }

        private static bool IsInner(long userIp, long begin, long end)
        {
            return (userIp >= begin) && (userIp <= end);
        }
        #endregion
    }
}
